package sk.sigp.aobot.swinggui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.DefaultCellEditor;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;

import org.apache.commons.io.IOUtils;

import sk.sigp.aobot.Colors;
import sk.sigp.aobot.Connect;
import sk.sigp.aobot.Utils;
import sk.sigp.aobot.base.Buddy;
import sk.sigp.aobot.base.BuddyComparator;
import sk.sigp.aobot.base.DoubleVal;
import sk.sigp.aobot.base.MessageListener;
import sk.sigp.aobot.base.StaticUtils;
import sk.sigp.aobot.client.BotCore;
import sk.sigp.aobot.swinggui.utils.GroupTableModel;
import sk.sigp.aobot.swinggui.utils.HyperTextListener;
import sk.sigp.aobot.swinggui.utils.NotifiableByHyperTextListener;
import sk.sigp.aobot.swinggui.utils.StringActionListener;

/**
 * main frame window
 * @author mathew
 *
 */
public class MainFrame extends JFrame implements NotifiableByHyperTextListener,
		MessageListener {

	private static final long serialVersionUID = 3303015098454625532L;

	private Color color = Colors.FOREGROUND;

	private Connect connect;
	
	private String txt = "";

	private JEditorPane area;
	private JDialog scriptDlg;
	private JPanel scriptPanelCenter;
	private JPanel downPanel;
	private JPanel centerPanel;
	private JPanel rightPanel;
	private JPanel buddyToolPanel;
	private JPanel contentPanel;
	private JButton scriptButton;
	private JButton colorButton;
	private JButton sendMessageButton;
	private JButton executeScriptButton;
	private JButton addBuddyButton;
	private JButton removeBuddyButton;
	private JButton leaveGroupButton;
	private JTextArea scriptTextArea;
	private JTextField messageTextField;
	private JTextField toTextField;
	private JCheckBox groupTellCheckBox;
	private JList buddyList;
	private JTable groupTable;
	private JScrollPane centerScrollPane;
	private JScrollPane buddyScrollPane;
	private JScrollPane groupScrollPane;
	private JSplitPane groupBuddySplitter;
	private JSplitPane mainSplitter;
	
	private ActionListener sendMessageListener;
	private StringActionListener groupButtonListener;

	private DefaultListModel buddyModel;
	private GroupTableModel groupModel;
	private List<Buddy> buddyData = new ArrayList<Buddy>();
	
	private MainFrame getThis() {
		return this;
	}
	
	public Color getColor() {
		return color;
	}

	public void setColor(Color color) {
		if (color!=null) {
			this.color = color;
			getColorButton().setBackground(color);
		}
	}

	public void buddyUpdate(final String buddy, final int status) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				// update
				Buddy budy = new Buddy();
				budy.name = buddy;
				budy.online = status;
				if (status!=-1) {
					if (buddyData.contains(budy)) {
						Buddy b = buddyData.get(buddyData.indexOf(budy));
						b.online = status;
					} else {
						buddyData.add(budy);
					}
				} else 
					buddyData.remove(budy);
				// sort
				Collections.sort(buddyData, new BuddyComparator());
				// fill model
				getBuddyModel().removeAllElements();
				for (Buddy b : buddyData)
					getBuddyModel().addElement(b);
			}
		});
	}
	
	public void groupAdd(final String group) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				getGroupModel().addGroup(group);				
			}
		});
	}
	
	public void groupRemove(final String name) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				// update
				getGroupModel().removeGroup(name);				
			}
		});		
	}
	
	public void invite(String userName) {
		int res = JOptionPane.showConfirmDialog(this, "Would you like to join priv. chat of "+userName+"?");
		if (JOptionPane.YES_OPTION==res) getBotCore().joinPrivateGroup(userName);
	}
	
	public void messageRecieved(final String message) {
//		System.out.println("msg:"+message);
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				String date = StaticUtils.actualTime();
				txt = "<font color=" + Utils.colorToRgb(Colors.FOREGROUND) + ">" +						
						txt + date + message
						+ "</font><br/>";
				getArea().setText("<html><body>" + txt + "</body></html>");

				getArea().repaint();
			}
		});
	}

	public void messageRecieved(String data, String group) {
//		System.out.println("group:"+group+", data:"+data);
		int id = getGroupModel().getData().indexOf(new DoubleVal(group,false));
		if (id!=-1 && getGroupModel().getData().get(id).getData())
			messageRecieved(data);
		if (id==-1)
			messageRecieved(data);
	}
	
	public void sendMessage(String messageText, boolean fromScript) {
		String txt = messageText;
		if (!Colors.FOREGROUND.equals(color)) {
			if (!fromScript)
				txt = "<font color=\""+Utils.colorToRgb(color)+"\">"
					+ txt + "</font>";
		}
		if (getGroupTellCheckBox().isSelected()) {
			if (txt.length()==0)
				return;
			Connect.scriptGroupTell(getToTextField().getText(), txt);
			getMessageTextField().setText("");
		} else {
			if (txt.length()==0)
				return;
			Connect.scriptTell(getToTextField().getText(), txt);
			getMessageTextField().setText("");
		}
	}
	
	public StringActionListener getGroupButtonListener() {
		if (groupButtonListener==null) {
			groupButtonListener=new StringActionListener() {
				public void action(String data) {
					GroupFrame gf = new GroupFrame(data,getConnect(),getThis());
					gf.setVisible(true);
				}
			};
		}
		return groupButtonListener;
	}
		
	public ActionListener getSendMessageListener() {
		if (sendMessageListener==null) {
			sendMessageListener = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (getConnect().getCore().isConnected())
						sendMessage(getMessageTextField().getText(),false);
					else
						messageRecieved("cant send message, not connected");
				}
			};
		}
		return sendMessageListener;
	}
	
	public JEditorPane getArea() {
		if (area == null) {
			area = new JEditorPane();
			area.setEditable(false);
			area.setContentType("text/html");
			area.setBackground(Colors.BACKGROUND);
			area.setForeground(Colors.FOREGROUND);

			area.addHyperlinkListener(new HyperTextListener(getConnect(),this));			
		}
		return area;
	}
	
	public JDialog getScriptDlg() {
		if (scriptDlg==null) {
			scriptDlg = new JDialog(this,"Script Exec");
			scriptDlg.setBounds(50,50, 700, 500);
			scriptDlg.setModal(false);
			scriptDlg.setContentPane(getScriptPanelCenter());			
		}
		return scriptDlg;
	}
	
	public JTextArea getScriptTextArea() {
		if (scriptTextArea==null) {
			try {
				scriptTextArea = new JTextArea( IOUtils.toString(Connect.class.getClassLoader().getResourceAsStream("default.bsh")) );
				scriptTextArea.setFont(new Font("Courier new",0,12));			
				scriptTextArea.setForeground(Colors.FOREGROUND);
				scriptTextArea.setBackground(Colors.BACKGROUND);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		return scriptTextArea;
	}

	public JPanel getScriptPanelCenter() {
		if (scriptPanelCenter==null) {
			scriptPanelCenter = new JPanel(new BorderLayout());
			scriptPanelCenter.add(new JScrollPane( getScriptTextArea() ),BorderLayout.CENTER);
			scriptPanelCenter.add(getScriptButton(),BorderLayout.SOUTH);

		}
		return scriptPanelCenter;
	}
	
	public JButton getScriptButton() {
		if (scriptButton==null) {
			scriptButton = new JButton("run script");
			scriptButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getConnect().runScript(getScriptTextArea().getText());
				}
			});			
		}
		return scriptButton;
	}
	
	public JButton getColorButton() {
		if (colorButton==null) {
			colorButton=new JButton();
			colorButton.setBackground(color);
			colorButton.setPreferredSize(new Dimension(30,30));
			colorButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {			
					Color tempColor =  JColorChooser.showDialog(getThis(), "Change text color", color);
					if (tempColor!=null) {
						color = tempColor;
						colorButton.setBackground(color);
					}
				}
			});
		}
		return colorButton;
	}
	
	public JPanel getDownPanel() {
		if (downPanel==null) {
			downPanel= new JPanel();
			downPanel.setMinimumSize(new Dimension(0, 50));
			downPanel.add(getColorButton());
			downPanel.add(getMessageTextField());
			downPanel.add(getGroupTellCheckBox());
			downPanel.add(getToTextField());
			downPanel.add(getSendMessageButton());
			downPanel.add(getExecuteScriptButton());
		}
		return downPanel;
	}
	
	public JTextField getMessageTextField() {
		if (messageTextField==null) {
			messageTextField=new JTextField();
			messageTextField.setBackground(Colors.BACKGROUND);
			messageTextField.setForeground(Colors.FOREGROUND);
			messageTextField.setCaretColor(Colors.CARET);
			messageTextField.setPreferredSize(new Dimension(300, 30));
			messageTextField.addActionListener(getSendMessageListener());
		}
		return messageTextField;
	}
	
	public JTextField getToTextField() {
		if (toTextField==null) {
			toTextField=new JTextField("Oest");
			toTextField.setBackground(Colors.BACKGROUND);
			toTextField.setForeground(Colors.FOREGROUND);
			toTextField.setCaretColor(Colors.CARET);
			toTextField.setPreferredSize(new Dimension(100, 30));
		}
		return toTextField;
	}
	
	public JCheckBox getGroupTellCheckBox() {
		if (groupTellCheckBox==null) {
			groupTellCheckBox=new JCheckBox("grp? (tell)", false);
		}
		return groupTellCheckBox;
	}
	
	public JButton getSendMessageButton() {
		if (sendMessageButton==null) {
			sendMessageButton=new JButton("send");
			sendMessageButton.addActionListener(getSendMessageListener());
		}
		return sendMessageButton;
	}
	
	public JScrollPane getCenterScrollPane() {
		if (centerScrollPane==null) {
			centerScrollPane=new JScrollPane(getArea());
		}
		return centerScrollPane;
	}
	
	public DefaultListModel getBuddyModel() {
		if (buddyModel==null) {
			buddyModel = new DefaultListModel();
		}
		return buddyModel;
	}
	
	public JList getBuddyList() {
		if (buddyList==null) {
			buddyList=new JList(getBuddyModel());
			buddyList.setBackground(Colors.BACKGROUND);
			buddyList.setForeground(Colors.FOREGROUND);
			buddyList.setCellRenderer(new BuddyRenderer());
			buddyList.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					Object o = buddyList.getSelectedValue();
					if (o instanceof Buddy) {
						Buddy b = (Buddy) o;
						tellActivated(b.name);
					}
				}
			});
		}
		return buddyList;
	}

	public GroupTableModel getGroupModel() {
		if (groupModel==null) {
			groupModel=new GroupTableModel();
		}
		return groupModel;
	}
		
	public JTable getGroupTable() {
		if (groupTable==null) {
			groupTable = new JTable(getGroupModel());
			groupTable.setBackground(Colors.BACKGROUND);
			groupTable.setForeground(Colors.FOREGROUND);
			groupTable.getColumnModel().getColumn(1).setMaxWidth(30);
			groupTable.getColumnModel().getColumn(2).setMaxWidth(30);
			groupTable.getColumnModel().getColumn(0).setCellRenderer(new TableCellRenderer() {
			
				public Component getTableCellRendererComponent(JTable table, Object value,
						boolean isSelected, boolean hasFocus, int row, int column) {
					JLabel lab = new JLabel(value.toString());
					lab.setForeground(Colors.FOREGROUND);
					lab.setBackground(Colors.BACKGROUND);
					lab.setOpaque(true);
					if (isSelected)
						lab.setBackground(Colors.SELECTED);
					return lab;
				}
			});
			groupTable.getColumnModel().getColumn(1).setCellRenderer(new TableCellRenderer() {
			
				public Component getTableCellRendererComponent(JTable table, Object value,
						boolean isSelected, boolean hasFocus, int row, int column) {
					JCheckBox ch = new JCheckBox();
					if (value instanceof Boolean) {
						Boolean bx = (Boolean) value;
						ch.setSelected(bx);
					}
					return ch;
				}
			});
			groupTable.getColumnModel().getColumn(2).setCellRenderer(new TableCellRenderer() {
				
				public Component getTableCellRendererComponent(JTable table, Object value,
						boolean isSelected, boolean hasFocus, int row, int column) {
					JButton ch = new JButton("o");
					return ch;
				}
			});
			JCheckBox cb = new JCheckBox();
			groupTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(cb) );
			groupTable.getColumnModel().getColumn(2).setCellEditor(new ButtonTableEditor(getGroupModel(),getGroupButtonListener()) );
			
			groupTable.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					Object o = getGroupModel().getValueAt(groupTable.getSelectedRow(), 0);
					if (o instanceof String) {
						String group = (String) o;
						groupActivated(group);
					}
				}
			});
			
		}
		return groupTable;
	}

	public JPanel getCenterPanel() {
		if (centerPanel==null) {
			centerPanel=new JPanel();
			centerPanel.setLayout(new BorderLayout());
			centerPanel.add(getCenterScrollPane(), BorderLayout.CENTER);
		}
		return centerPanel;
	}
	
	public JScrollPane getBuddyScrollPane() {
		if (buddyScrollPane==null) {
			buddyScrollPane=new JScrollPane(getBuddyList());
		}
		return buddyScrollPane;
	}
	
	public JScrollPane getGroupScrollPane() {
		if (groupScrollPane==null) {
			groupScrollPane=new JScrollPane(getGroupTable());
			groupScrollPane.setPreferredSize(new Dimension(0, 70));
		}
		return groupScrollPane;
	}
	
	public JButton getExecuteScriptButton() {
		if (executeScriptButton==null) {
			executeScriptButton=new JButton("exe");
			executeScriptButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getScriptDlg().setVisible(true);
				}
			});
		}
		return executeScriptButton;
	}
	
	public JSplitPane getGroupBuddySplitter() {
		if (groupBuddySplitter==null) {
			groupBuddySplitter=new JSplitPane(
					JSplitPane.VERTICAL_SPLIT,
					getBuddyScrollPane(),
					getGroupScrollPane()
					);
			groupBuddySplitter.setDividerLocation(getHeight()-250);
			groupBuddySplitter.setDividerSize(2);
			groupBuddySplitter.setResizeWeight(1.0);
		}
		return groupBuddySplitter;
	}
	
	public JSplitPane getMainSplitter() {
		if (mainSplitter==null) {
			mainSplitter=new JSplitPane(
					JSplitPane.HORIZONTAL_SPLIT,true,
					getCenterPanel(),
					getRightPanel()
					);
			mainSplitter.setResizeWeight(1.0);
			mainSplitter.setDividerLocation(getWidth()-200);
			mainSplitter.setDividerSize(2);
		}
		return mainSplitter;
	}
	
	public JPanel getRightPanel() {
		if (rightPanel==null) {
			rightPanel=new JPanel();
			rightPanel.setLayout(new BorderLayout());
			rightPanel.add(getGroupBuddySplitter(), BorderLayout.CENTER);
			rightPanel.add(getBuddyToolPanel(), BorderLayout.NORTH);
		}
		return rightPanel;
	}
	
	public JPanel getBuddyToolPanel() {
		if (buddyToolPanel==null) {
			buddyToolPanel=new JPanel();
			buddyToolPanel.setPreferredSize(new Dimension(0,35));
			buddyToolPanel.add(getAddBuddyButton());
			buddyToolPanel.add(getRemoveBuddyButton());		
			buddyToolPanel.add(getLeaveGroupButton());		
		}
		return buddyToolPanel;
	}
	
	public JButton getAddBuddyButton() {
		if (addBuddyButton==null) {
			addBuddyButton= new JButton("+m8");
			addBuddyButton.setPreferredSize(new Dimension(40,20));
			addBuddyButton.setMargin(new Insets(0,0,0,0));
			addBuddyButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getBotCore().addBuddy(getToTextField().getText());
				}
			});
		}
		return addBuddyButton;
	}
	
	public JButton getRemoveBuddyButton() {
		if (removeBuddyButton==null) {
			removeBuddyButton= new JButton("-m8");
			removeBuddyButton.setPreferredSize(new Dimension(40,20));
			removeBuddyButton.setMargin(new Insets(0,0,0,0));
			removeBuddyButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getBotCore().removeBuddy(getToTextField().getText());
				}
			});
		}
		return removeBuddyButton;
	}
	
	public JButton getLeaveGroupButton() {
		if (leaveGroupButton==null) {
			leaveGroupButton= new JButton("leave grp");
			leaveGroupButton.setPreferredSize(new Dimension(60,20));
			leaveGroupButton.setMargin(new Insets(0,0,0,0));
			leaveGroupButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getBotCore().leavePrivateGroup(getToTextField().getText());
				}
			});
		}
		return leaveGroupButton;
	}
	
	public JPanel getContentPanel() {
		if (contentPanel==null) {
			contentPanel=new JPanel();
			contentPanel.setLayout(new BorderLayout());
		}
		return contentPanel;
	}
	
	protected void initialize() {
		setContentPane(getContentPanel());
		setSize(700, 500);
		setLocation((int) Toolkit.getDefaultToolkit().getScreenSize()
				.getWidth()
				/ 2 - getWidth() / 2, (int) Toolkit.getDefaultToolkit()
				.getScreenSize().getHeight()
				/ 2 - getHeight() / 2);
		getContentPanel().add(getMainSplitter(), BorderLayout.CENTER);
		getContentPanel().add(getDownPanel(), BorderLayout.SOUTH);
		setTitle("Oest's Relay Chat, v" + Utils.VERSION);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	public MainFrame(Connect connect) {
		setConnect(connect);
		initialize();
		setColor(Colors.FOREGROUND);
	}
	
	public void groupActivated(String group) {
		getToTextField().setText(group);
		getGroupTellCheckBox().setSelected(true);		
	}

	public void notifyByHyperTextListener(String message) {
		messageRecieved(message);
	}

	protected BotCore getBotCore() {
		return getConnect().getCore();
	}
	
	public void tellActivated(String toUser) {
		getToTextField().setText(toUser);
		getGroupTellCheckBox().setSelected(false);		
	}
	
	public Connect getConnect() {
		return connect;
	}

	public void setConnect(Connect connect) {
		this.connect = connect;
	}
	
}
